/*
 * Copyright 2009 Armando Blancas
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package taskgraph.tasks.text;

import java.io.IOException;
import java.io.InterruptedIOException;

import taskgraph.ports.CharInputPort;
import taskgraph.ports.CharOutputPort;
import taskgraph.tasks.PrimitiveTask;


/**
 * Replicate a line of text N times.
 * 
 * <p>This task works in two modes:
 * 
 * <p>Mode 1: The task is initialized with both the line to replicate
 * and the number of times to replicate it; no input port is required.
 *  
 * <p>Mode 2: Each line read from the input port 
 * and written N times to the output port.
 * 
 * @author Armando Blancas
 * @see taskgraph.ports.CharInputPort
 * @see taskgraph.ports.CharOutputPort
 */
public class ReplicateLine extends PrimitiveTask {

	private CharInputPort input;
	private CharOutputPort output;
	private String inputLine;
	private int times;

	/**
	 * This constructor allows creating instances as beans.
	 */
    public ReplicateLine() {
    	// do nothing
    }

	/**
     * Creates a configured instance with an input port.
     * 
     * @param input The char input port.
     * @param output The char output port.
     * @param times The number of times to replicate an input line.
     */
    public ReplicateLine(final CharInputPort input, 
    		             final CharOutputPort output,
    		             final int times) {
    	setInput(input);
    	setOutput(output);
    	setTimes(times);
    }
    
	/**
     * Creates a configured instance with an input line.
     * 
     * @param output The char output port.
     * @param inputLine The single line to replicate.
     * @param times The number of times to replicate an input line.
     */
    public ReplicateLine(final CharOutputPort output,
    		             final String inputLine,
    		             final int times) {
    	setOutput(output);
    	setInputLine(inputLine);
    	setTimes(times);
    }
    
    /**
     * Gets the input port.
     * 
	 * @return The char input port.
	 */
	public CharInputPort getInput() {
		return input;
	}

	/**
	 * Gets the value of the input line to replicate.
	 * 
	 * @return The line to be replicated, as a {@code String}.
	 */
    public String getInputLine() {
		return inputLine;
	}
	
	/**
     * Gets the output port.
     * 
	 * @return The char output port.
	 */
	public CharOutputPort getOutput() {
		return output;
	}

	/**
     * Gets the number of times to replicate an input line.
     */
	public int getTimes() {
		return times;
	}

	/**
	 * Identify the mode by looking at the value of {@code inputLine}
	 * and do the work accordingly.
	 */
	@Override
    public void run() {
    	try {
    		if (inputLine != null) {
    			for (int i = 0; i < times; ++i) {
    				output.println(inputLine);
    			}
    		} else {
	    		while (!Thread.currentThread().isInterrupted()) {
	    			String line = input.readLine();
	    			if (line == null) {
	    				break;
	    			}
	    			for (int i = 0; i < times; ++i)
	    				output.println(line);
	            }
    		}
        } catch (InterruptedIOException ie) {
        	// interruption request
        } catch (IOException ioe) {
        	// pipe synch error
            log.error("ReplicateLine#run()", ioe);
        } finally {
			if (input != null) 
				input.close();
			output.close();
        }
    }

    /**
	 * Sets the input port.
	 * 
	 * @param input The char input port.
	 */
    public void setInput(final CharInputPort input) {
    	if (input == null)
    		throw new IllegalArgumentException("input == null");
 		this.input = input;
	}

	/**
	 * Sets the value of the input line to replicate.
	 * 
	 * @param inputLine The line to be replicated, as a {@code String}.
	 */
    public void setInputLine(String inputLine) {
    	if (inputLine == null)
    		throw new IllegalArgumentException("inputLine == null");
		this.inputLine = inputLine;
	}

	/**
	 * Sets the output port.
	 * 
	 * @param output The char output port.
	 */
    public void setOutput(final CharOutputPort output) {
    	if (output == null)
    		throw new IllegalArgumentException("output == null");
 		this.output = output;
	}

	/**
     * Sets the number of times to replicate an input line.
     * 
     * @param times The {@code int} number.
     */
	public void setTimes(int times) {
		this.times = times;
	}

}
